package org.rcy.framework.data.mybatis;

import org.apache.ibatis.binding.MapperProxyFactory;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.session.Configuration;
import org.rcy.framework.data.dao.BaseDao;
import org.rcy.framework.data.dao.MapperHelperFactory;
import org.rcy.framework.data.datasource.DataSourceChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tk.mybatis.mapper.mapperhelper.MapperHelper;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class MybatisRefresher {
	
	private static Logger logger = LoggerFactory.getLogger(DataSourceChangeListener.class);
	
	public static void refreshMybatis(Configuration configuration) {
		logger.info("Refresh mybatis...");
		//清除mappedStatements
		Arrays.asList("mappedStatements", "caches", "resultMaps", "parameterMaps", "keyGenerators", "sqlFragments")
				.forEach(fieldName -> ((Map<?, ?>) getField(configuration, fieldName)).clear());
		
		//清除loadedResources
		Set<String> loadedResources = getField(configuration, "loadedResources");
		List<String> mapperInterfaces = loadedResources.stream().filter(resource -> resource.startsWith("interface"))
				.map(resource -> resource.replace("interface ", "")).collect(Collectors.toList());
		loadedResources.clear();
		
		//清除knownMappers
		MapperRegistry mapperRegistry = configuration.getMapperRegistry();
		Map<Class<?>, MapperProxyFactory<?>> knownMappers = getField(mapperRegistry,"knownMappers");
		knownMappers.clear();

		// 重新加载Mapper
		MapperHelper mapperHelper = MapperHelperFactory.getMapperHelper();
		mapperInterfaces.forEach(interfaceName -> {
			try {
				Class<?> mapperInterface = Class.forName(interfaceName);
				configuration.addMapper(mapperInterface);
				//处理通用dao
				if(BaseDao.class.isAssignableFrom(mapperInterface)) {
					mapperHelper.processConfiguration(configuration, mapperInterface);
				}
			} catch (ClassNotFoundException e) {
				logger.error(e.getMessage());
			}
		});
		logger.info("Refresh mybatis OK.");
	}

	@SuppressWarnings("unchecked")
	private static <T> T getField(Object target, String fieldName) {
		try {
			Field field = target.getClass().getDeclaredField(fieldName);
			field.setAccessible(true);
			return (T) field.get(target);
		} catch (NoSuchFieldException | SecurityException | IllegalAccessException ex) {
			logger.error(ex.getMessage(), ex);
			return null;
		}
	}
}
